package org.budo.dubbo.protocol.http.authentication;

import java.io.Serializable;
import java.lang.reflect.Method;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.budo.dubbo.protocol.http.authentication.AuthenticationCheckService.Fail;
import org.budo.dubbo.protocol.http.exception.remoting.AuthenticationCheckException;
import org.budo.support.lang.util.BooleanUtil;
import org.budo.support.mvcs.Mvcs;
import org.budo.support.spring.aop.util.AopUtil;
import org.springframework.core.annotation.Order;

import lombok.extern.slf4j.Slf4j;

/**
 * Interceptor for 用户身份认证，Aop过滤器
 * 
 * @author lmw
 * @see org.budo.dubbo.protocol.http.authentication.AuthenticationCheck
 */
@Slf4j
@Order(1000)
public class AuthenticationCheckMethodInterceptor extends AbstractAuthenticationCheckInterceptor implements MethodInterceptor {
    public static final String REQUIRE_AUTHENTICATION_CHECK = "_requireAuthenticationCheck";

    public Object invoke(MethodInvocation invocation) throws Throwable {
        Method method = invocation.getMethod();

        Boolean requireAuthenticationCheck = (Boolean) Mvcs.getRequestAttribute(REQUIRE_AUTHENTICATION_CHECK);
        if (BooleanUtil.isFalse(requireAuthenticationCheck)) { // 如果第一个方法不需要，同一个请求里后面的就都不需要了
            return invocation.proceed();
        }

        // Aop跳过框架类
        if (AopUtil.aopShouldSkip(method)) {
            return invocation.proceed();
        }

        Class<?> type = invocation.getMethod().getDeclaringClass();
        requireAuthenticationCheck = AuthenticationCheckUtil.requireAuthenticationCheck_aop(type, method);

        Mvcs.setRequestAttribute(REQUIRE_AUTHENTICATION_CHECK, requireAuthenticationCheck); // 第一个方法存下来

        if (!requireAuthenticationCheck) {
            return invocation.proceed();
        }

        // 开始验证
        AuthenticationCheckService _authenticationCheckService = this.getAuthenticationCheckService();
        if (null == _authenticationCheckService) {
            log.error("#45 AuthenticationCheckService not found, this=" + this);
            return invocation.proceed();
        }

        Serializable _authenticationPrincipal = _authenticationCheckService.getAuthenticationPrincipal();

        // 验证失败
        if ((null == _authenticationPrincipal || _authenticationPrincipal instanceof Fail)) {
            return this.handleAuthFailed(invocation, _authenticationPrincipal);
        }

        // 验证成功
        return invocation.proceed();
    }

    protected Object handleAuthFailed(MethodInvocation invocation, Serializable userPrincipal) {
        log.error("#47 userPrincipal=" + userPrincipal + ", checkService=" + this.getAuthenticationCheckService() + ", invocation=" + invocation + ", this=" + this);

        throw new AuthenticationCheckException(invocation.getMethod(), (Fail) userPrincipal); // 异常跳出流程
    }
}
